package org.upfrost.mapping;

import java.beans.IntrospectionException;
import java.util.List;

import junit.framework.TestCase;


import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.upfrost.Mapper;
import org.upfrost.mapping.ClassProxy;
import org.upfrost.mapping.Mapping;
import org.upfrost.mapping.classes.TestClass1;
import org.upfrost.mapping.classes.TestClass2;
import org.upfrost.mapping.classes.TestClass3;
import org.upfrost.mapping.classes.TestClass4;
import org.upfrost.mapping.classes.TestClass5;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class MappingCreationTest extends TestCase
{
	private Mapper m_mapper;
	
	@Before
	public void setUp() throws Exception 
	{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setDriverClass("org.hsqldb.jdbcDriver");
		dataSource.setJdbcUrl("jdbc:hsqldb:mem:test");
		dataSource.setUser("sa");
		dataSource.setPassword("");
		
		m_mapper = new Mapper(dataSource);
	}

	@Test
	public void testProxyNoAnnotation() throws IntrospectionException
	{
		String[] propnames = { "id", "strValue", "someDate" };
		String[] sqlnames = { "id", "strvalue", "somedate" };
		testGeneric(TestClass1.class, propnames, sqlnames, 3, null, false, false);
	}

	@Test
	public void testProxyAnnotationAccessorField() throws IntrospectionException
	{
		String[] propnames = { "id", "strValue", "someDate" }; 
		String[] sqlnames = { "id", "value", "when" }; 
		testGeneric(TestClass2.class, propnames, sqlnames, 3, 0, true, true);
	}

	@Test
	public void testProxyAnnotationAccessorMethod() throws IntrospectionException
	{
		String[] propnames = { "id", "strValue", "someDate" }; 
		String[] sqlnames = { "id", "value", "when" }; 
		testGeneric(TestClass3.class, propnames, sqlnames, 3, 0, false, false);
	}

	@Test
	public void testProxyAnnotationAccessorWrong() throws IntrospectionException
	{
		String[] propnames = { "id" }; 
		String[] sqlnames = { "myId" };
		testGeneric(TestClass5.class, propnames, sqlnames, 1, 0, false, false);
	}

	 public <T> void  testGeneric(Class<T> clazz, String[] propnames, String[]sqlnames, int mappingCount, Integer keyIndex, boolean fieldAccess, boolean generatedValue) throws IntrospectionException
	{
		m_mapper.addAnnotated(clazz);
		
		ClassProxy<T> proxy = m_mapper.getClassProxy(clazz);
		List<Mapping<?>> mappings = proxy.getMappingListCopy();
		
		Assert.assertEquals(mappingCount, mappings.size());

		for (int i=0; i<propnames.length; i++)
		{
			Mapping<?> m = proxy.getPropertyMapping(propnames[i]);
			Mapping<?> m2 = proxy.getMappingFromSqlColumn(sqlnames[i]);
			
			Assert.assertNotNull(m);
			Assert.assertEquals(m, m2);
			if (fieldAccess)
			{
				Assert.assertTrue(m.isAccessedByField());
				Assert.assertFalse(m.isAccessedByAccessorMethod());
			}
			else
			{
				Assert.assertFalse(m.isAccessedByField());
				Assert.assertTrue(m.isAccessedByAccessorMethod());
			}
			
			if (keyIndex != null && keyIndex == i)
			{
				Assert.assertTrue(m.isKey());
				if (generatedValue)
					Assert.assertTrue(m.isKeyGenerated());
				else
					Assert.assertFalse(m.isKeyGenerated());
			}
			else
			{
				Assert.assertFalse(m.isKey());
				Assert.assertFalse(m.isKeyGenerated());
			}
				
		}
	}
	

	@Test
	public void testProxyAnnotationAccessorBoth() throws IntrospectionException
	{
		try {
			m_mapper.addAnnotated(TestClass4.class);	

			Assert.assertTrue("TestClass4 has JPA annotation on fields and accessor, and shouldn't be accepted", false);

		} catch (Exception e)
		{
			ClassProxy<TestClass4> proxy = m_mapper.getClassProxy(TestClass4.class);
			Assert.assertNull(proxy);
		}
		
	}

	
}
